home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
t3_1
/
doc.lha
/
documentation
/
manual
/
syntax.mss
< prev
next >
Wrap
Text File
|
1987-06-30
|
27KB
|
652 lines
@part[SYNTAX, root "TMAN.MSS"] @Comment{-*-System:TMAN-*-}
@chap[Syntax]
@label[SyntaxChapter] @Comment{ref: implementation chapter}
@label[Last T Chapter] @Comment{ref: implementation chapter}
The @Tau[] standard environment includes routines which perform
syntactic and semantic analysis of @Tau[] programs.
There are two such subsystems within @Tau[], corresponding to the
language's two syntactic levels (see chapter @ref[semantics chapter]).
These are the @i[reader] and the @i[compiler].
In an attempt to make each of these subsystems as generally useful and
flexible as possible, they are not restricted to processing the language
as described in this manual. Instead, they each operate with respect to
parameter clusters known as @iix[read tables], in the case of the
reader, or @iix[syntax tables], in the case of the compiler.
@section[The reader]
@label[READER] @Comment{ref: semantics}
The @iix[reader] is a procedure available in the standard environment as
the value of the variable @tc[READ-OBJECT]. Conceptually, the reader
coerces a stream of characters (@ix[external representation]) to a stream of
objects (internal representations) via a mechanism
known as @i[parsing].
@AnEquivE[Tfn="READ",Efn="READ"]
@desc[@el[](READ-OBJECT @i[stream] @i[read-table]) @yl[] @i[object] @r[or] @i[end-of-file]]
@tc[READ-OBJECT] employs the @tc[READ-CHAR] (page @pageref[READ-CHAR])
and @tc[UNREAD-CHAR] (page @pageref[UNREAD-CHAR]) operations in
order to parse an object according to the stream's read table.
If the stream is empty, the end-of-file token is returned.
@tc[READ-OBJECT] is called by the default method for the @tc[READ]
operation (page @pageref[READ]), so the reader is usually invoked
indirectly by calling
@tc[READ], not by calling @tc[READ-OBJECT] directly. When invoked
from @tc[READ], the second argument to @tc[READ-OBJECT] is obtained
by calling the @tc[STREAM-READ-TABLE] operation on the stream.
@EndDesc[READ-OBJECT]
The reader works as follows:
Any whitespace characters (space, tab, newline, carriage return, line
feed, or form feed) are read and ignored. A non-whitespace character is
obtained; call it @i[c].
@index[Whitespace]
If @i[c] is a read-macro character, the reader invokes a specialist routine
to handle a syntactic construct introduced by the read-macro character.
If @i[c] is not a read-macro character, then characters are read and
saved until a @i[delimiter] character is read. A delimiter character is
either a whitespace character, or one of the following: @tc[(] (left
parenthesis), @tc[)] (right parenthesis), @tc<[>, @tc<]>, @tc<{>,
@tc<}>, or @tc[;] (semicolon). If the sequence of characters beginning
with @i[c] and going up to but not including the delimiter is parsable
as a number, then the sequence is converted to a number, which is
returned.
Otherwise the sequence is converted to a symbol.
@index[Numbers]
@index[Symbols]
@index[Delimiter characters]
@index[Constituent characters]
The @i[escape character], backslash (@tc[\]), may be used within a
run of constituent characters to include unusual characters in a
symbol's print name. In this case, the escaped character (i.e. the character
following the escape character) is treated as if it were a constituent
character, and is not converted to upper case if it is a lower case
letter. For example:
@begin[ProgramExample]
abc\;def @r[reads the same as] #[Symbol "ABC;DEF"]
\a\bcdef @r[reads the same as] #[Symbol "abCDEF"]
\12345 @r[reads the same as] #[Symbol "12345"]
\'12345 @r[reads the same as] #[Symbol "'12345"]
@end[ProgramExample]
@dc{ talk about dot? }
The following are standard read-macro characters:
@begin[description]
@tc["]@\Doublequote: introduces a string. Characters are read until another doublequote
character is found which does not immediately follow a backslash (@tc[\]),
and a string is returned. Within a string, backslash acts as an escape
character, so that doublequotes and backslashes may appear in strings.
@index[strings]
@tc[']@\Quote: @tc['@i[object]] reads the same as @tc[(QUOTE @i[object])].
@tindex[QUOTE]
@tc[(]@\Left parenthesis: begins a list.@index[parentheses]
@tc[)]@\Right parenthesis: ends a list or vector, and is illegal in other
contexts.
@tc[`]@\Backquote: see section @ref[backquote section].@index[Backquote]
@tc[,]@\Comma: this is part of the backquote syntax.
@tc[;]@\Semicolon: introduces a comment. Characters are read and discarded
until a newline is encountered, at which point the parsing process starts over.
@label[SEMICOLON]
@index[Comments]
@tc[#]@\Sharp-sign: another dispatch to a specialist routine is
performed according to the character following the @tc[#].
@end[description]
Standard sharp-sign forms:
@begin[description]
@tc[#\]@\Character syntax. See section @ref[character syntax].
@tc[#x]@\@ix[Hexadecimal] input. An integer following the @tc[#x]
is read in base 16.
@tc[#o]@\@ix[Octal] input. An integer following the @tc[#o] is read in base 8.
@tc[#b]@\Binary input. An integer following the @tc[#b] is read in base 2.
@tc[#(...)]@\Vector. The elements of a vector are read between the parentheses,
and the vector is returned.
@index[Vectors]
@tc{#[...]}@\This syntax is used for certain kinds of re-readable objects.
It also provides an alternate syntax for characters and symbols.
The brackets enclose a sequence of objects; the first should be a symbol
which keys the type of the resulting object, e.g. @tc[CHAR] or @tc[SYMBOL].
@index[Characters]@index[Symbols]
For example,
@begin[ProgramExample]
#[Char 65] @r[represents the same object as] #\A
#[Symbol "FOO"] @r[represents the same object as] FOO
@end[ProgramExample]
This syntax is used by the printer when necessary, for example:
@begin[ProgramExample]
(STRING->SYMBOL "") @ev[] #[Symbol ""]
(ASCII->CHAR 128) @ev[] #[Char 128]
@end[ProgramExample]
@tc[#{...}]@\This is the syntax used by the printer for objects which
have no reader syntax. When the reader encounters the sequence @tc[#{]
it signals an error.
@end[description]
@section[Read tables and read macros]
@label[READTABLES] @Comment{ref: semantics chapter, streams chapter}
@ix[Read tables] package a number of parameters for use by programs which
parse, generate, or otherwise manipulate external syntax of programs and
objects. In particular, every read table contains a table which
maps characters to objects which describe their lexical
properties.
There is a standard read table which contains the standard read syntax
for all characters. In order to define nonstandard read syntax, one
must create a new read table using @tc[MAKE-READ-TABLE], and arrange
for @tc[READ-OBJECT] to use that read table instead of the standard
read table, e.g. by doing @wt[(SET (STREAM-READ-TABLE ...) ...)].
@begin[group]
@desc[(MAKE-READ-TABLE @i[read-table identification]) @yl[] @i[new-read-table]]
Creates a new read table which is a copy of @i[read-table].
@i[Identification] serves for debugging purposes only.
@begin[ProgramExample]
(DEFINE *MY-READ-TABLE*
(MAKE-READ-TABLE *STANDARD-READ-TABLE* '*MY-READ-TABLE*))
@end[ProgramExample]
@EndDesc[MAKE-READ-TABLE]
@end[group]
@desc[*STANDARD-READ-TABLE* @yl[] @i[read-table]]
The standard @Tau[] read table.
@EndDesc[*STANDARD-READ-TABLE*]
@desc[*VANILLA-READ-TABLE* @yl[] @i[read-table]]
The value of @tc[*VANILLA-READ-TABLE*] is a read table in which all
all graphic characters have ordinary non-read-macro constituent
syntax, whitespace characters have whitespace syntax, and
other characters (e.g. control characters) are illegal.
@begin[ProgramExample]
(WITH-INPUT-FROM-STRING (STREAM " foo () ")
(SET (STREAM-READ-TABLE STREAM) *VANILLA-READ-TABLE*)
(LIST (READ STREAM) (READ STREAM)))
@ev[] (FOO #[Symbol "()"])
@end[ProgramExample]
@EndDesc[*VANILLA-READ-TABLE*]
@info[NOTES="Settable"]
@desc[(READ-TABLE-ENTRY @i[table character]) @yl[] @i[syntax]]
Access @i[character]'s read syntax in @i[table].
The entry for a given character is some object which represents the
character's lexical properties, for example, whether it is
a constituent, whitespace, or read-macro character.
For read-macro characters, the entry is a procedure
for parsing the read-macro construct.
@index[Read macros]
Values suitable to be stored in read tables may be obtained
by accessing existing entries in the standard read table. For example:
@begin[ProgramExample]
(SET (READ-TABLE-ENTRY *MY-READ-TABLE* #\;)
(READ-TABLE-ENTRY *STANDARD-READ-TABLE* #\:))
@end[ProgramExample]
makes the read syntax of semicolon in @tc[*MY-READ-TABLE*] be the
same as the standard read syntax of colon (which is a
contituent character).
To define a read macro, do
@begin[ProgramExample]
(SET (READ-TABLE-ENTRY @i[read-table] @i[character]) @i[procedure])
@end[ProgramExample]
where @i[procedure] is a procedure taking two arguments: a stream
and a character. The stream is the stream which is currently being
parsed by @tc[READ-OBJECT]. It may be passed as the stream argument
to input routines like @tc[READC] and @tc[READ-REFUSING-EOF] if the
read-macro needs to parse further characters from the input stream.
The character is the character which caused the read macro to be
invoked; that is, it is the character under which the procedure is
stored in the read table.
Example:
@begin[ProgramExample]
(SET (READ-TABLE-ENTRY *MY-READ-TABLE* #\')
(LAMBDA (STREAM CH)
(IGNORE CH)
(LIST 'QUOTE (READ-REFUSING-EOF STREAM))))
@end[ProgramExample]
Note that the standard read table and the vanilla read table
are immutable, and so their entries may not be changed.
@EndDesc[READ-TABLE-ENTRY]
@desc[*NOTHING-READ* @yl[] @i[object]]
Read macros should return this object, which is treated specially
by the reader, if they want to return no object.
For example, the semi-colon (comment) read-macro might be defined as follows:
@begin[ProgramExample]
(SET (READ-TABLE-ENTRY *MY-READ-TABLE* #\;)
(LAMBDA (STREAM CH)
(ITERATE LOOP ()
(LET ((C (READC STREAM)))
(COND ((EOF? C) C)
((CHAR= C #\NEWLINE) *NOTHING-READ*)
(ELSE (LOOP)))))))
@end[ProgramExample]
@EndDesc[*NOTHING-READ*]
@info[NOTES="Operation"]
@desc[(DELIMITING-READ-MACRO? @i[procedure]) @yl[] @i[boolean]]
If an object which returns true to the @tc[DELIMITING-READ-MACRO?] operation is
stored in a read table under a given character, then the reader will
treat the character as a delimiter (non-constituent) character.
By default, read-macro procedures return false to this predicate. Thus
to make a read-macro character be a delimiting character also (as
are parentheses and semicolon in the standard read table), its
read table entry should handle this operation by returning true.
@begin[ProgramExample]
(SET (READ-TABLE-ENTRY *MY-READ-TABLE* #\~)
(OBJECT (LAMBDA (STREAM CH)
...)
((DELIMITING-READ-MACRO? SELF) T)))
@end[ProgramExample]
@EndDesc[DELIMITING-READ-MACRO?]
@desc[(MAKE-LIST-READER) @yl[] @i[list-reader]]
The two procedures @tc[MAKE-LIST-READER] and @tc[LIST-TERMINATOR]
can be used together to define read macros which behave syntactically
like parentheses.
Each call to @tc[MAKE-LIST-READER] returns an object which is a
procedure of two arguments called a @i[list reader.] Calling
@tc[LIST-TERMINATOR] on a list reader will return another object called
its @i[list terminator.]
List readers and terminators are suitable for entry in read tables.
A list reader acts as a read macro which reads a sequence of objects,
terminated by a character whose read syntax is the corresponding list
terminator. For example, the standard syntax for left and right
parentheses might be defined as follows:
@begin[ProgramExample]
(LET ((LIST-READER (MAKE-LIST-READER)))
(SET (READ-TABLE-ENTRY *STANDARD-READ-TABLE* #\LEFT-PAREN)
LIST-READER)
(SET (READ-TABLE-ENTRY *STANDARD-READ-TABLE* #\RIGHT-PAREN)
(LIST-TERMINATOR LIST-READER)))
@end[ProgramExample]
Like any read-macro procedure, a list reader is a procedure of two
arguments. The first argument must be a stream, and the second is
ignored. Thus instead of being stored in a read table, it may be
called from another read-macro procedure. For example, the following
makes @tc<[...]> an alternative read syntax for vectors:
@begin[ProgramExample]
(LET ((LIST-READER (MAKE-LIST-READER)))
(SET (READ-TABLE-ENTRY *MY-READ-TABLE* #\LEFT-BRACKET)
(OBJECT (LAMBDA (STREAM CH)
(LIST->VECTOR (LIST-READER STREAM CH)))
((DELIMITING-READ-MACRO? SELF) T)))
(SET (READ-TABLE-ENTRY *MY-READ-TABLE* #\RIGHT-BRACKET)
(LIST-TERMINATOR LIST-READER)))
@end[ProgramExample]
List readers and terminators handle the @tc[DELIMITING-READ-MACRO?]
operation by returning true.
@EndDesc[MAKE-LIST-READER]
@desc[(LIST-TERMINATOR @i[list-reader]) @yl[] @i[list-terminator]]
Given a list reader, returns its list terminator. See @tc[LIST-READER],
above.
@EndDesc[LIST-TERMINATOR]
@section[Standard compiler]
A @iixs[compiler] is a procedure which accepts an expression and a
syntax table, and returns a @i[compiled code] object. A compiled
code object may be executed in a given environment. Note that
the term @qu"compiler" is used in a technical sense
and encompasses not only compilers such as TC (section @ref[COMFILE]) which
produce machine instructions, but also programs such as the standard
compiler (which is called by @tc[EVAL]) which operate internally by
producing intermediate code or by interpreting source code directly.
Often programs like these are called @i[interpreters] instead of
@i[compilers.]
@index[Expression syntax]
A given @Tau[] implementation may have several compilers.
@tc[STANDARD-COMPILER] should be one of these compilers.
@Timp[] 2.7 also provides a compiler called TC, which is
described in section @ref[COMFILE].
@desc[(EVAL @i[expression] @i[environment]) @yl[] @i[object]]
Evaluates @i[expression] in @i[environment]. Evaluation is performed as
a two-stage process: first, the standard compiler compiles the
expression, producing a compiled code object; then the compiled code
object is invoked in the given environment.
@begin[TEG]
(EVAL @i[expression] @i[environment])
@ce[]
(RUN-COMPILED-CODE (STANDARD-COMPILER @i[expression]
(ENV-SYNTAX-TABLE @i[environment]))
@i[environment])
@end[TEG]
@EndDesc[EVAL]
@desc[(STANDARD-COMPILER @i[expression] @i[syntax-table]) @yl[] @i[compiled-code]]
Compiles @i[expression]. An implementation of @Tau[] may provide several
compilers, of which @tc[STANDARD-COMPILER] will be the one which is
invoked by @tc[EVAL].
@EndDesc[STANDARD-COMPILER]
@desc[(RUN-COMPILED-CODE @i[compiled-code] @i[environment]) @yl[] @i[object]]
Invokes a compiled code object.
@BeginInset[Bug:]
In @Timp[] 2.7, the environment passed to @tc[RUN-COMPILED-CODE]
must be the same as the one whose syntax table was passed
to @tc[STANDARD-COMPILER].
@EndInset[]
@EndDesc[RUN-COMPILED-CODE]
@section[Syntax tables]
@label[Syntax tables section] @Comment{ref: semantics}
@index[Syntax tables]
@index[Reserved words]
@index[Special forms]
A syntax table maps symbols to @iix[syntax descriptors]. Every syntax
descriptor is itself either a macro expander, or a unique token
identifying a primitive special form type.
Every locale has an associated syntax table. A locale's syntax table
contains definitions of special forms which are local to the locale. Each
such syntax table inherits entries lexically from the syntax tables
of enclosing locales.
@iix[Macros] provide a mechanism for extending the syntax of @Tau[]
by means of source-to-source transformations.
As in many Lisp dialects, the macro facility in @Tau[] provides a powerful
tool for amplifying the expressiveness of the language. But like any
powerful tool, macros may be abused. They may easily lead to programs
that are very hard to understand.
Macros are defined by entering syntax descriptor objects known as
@iix[macro expanders] into syntax tables; see
@tc[SYNTAX-TABLE-ENTRY] and @tc[DEFINE-SYNTAX], below.
Macros may also be defined locally to a file or expression using
@tc[DEFINE-LOCAL-SYNTAX] or @tc[LET-SYNTAX].
Procedure integration is preferable to the use of macros in situations
where either would be applicable. See @tc[DEFINE-INTEGRABLE], page
@pageref[DEFINE-INTEGRABLE].
@desc[(ENV-SYNTAX-TABLE @i[environment]) @yl[] @i[syntax-table]]
Returns the syntax table associated with @i[environment].
@EndDesc[ENV-SYNTAX-TABLE]
@desc[(MAKE-SYNTAX-TABLE @i[syntax-table] @i[identification]) @yl[] @i[syntax-table]]
Creates a new syntax table inferior to the given syntax table.
Note that syntax tables are created implicitly by @tc[MAKE-LOCALE]
(page @pageref[MAKE-LOCALE]).
@EndDesc[MAKE-SYNTAX-TABLE]
@desc[*STANDARD-SYNTAX-TABLE* @yl[] @i[syntax-table]]
A syntax table with entries for all standard @Tau[] reserved words.
@begin[ProgramExample]
*STANDARD-SYNTAX-TABLE* @ce[] (ENV-SYNTAX-TABLE-ENTRY *STANDARD-ENV*)
@end[ProgramExample]
@EndDesc[*STANDARD-SYNTAX-TABLE*]
@info[NOTES="Settable"]
@desc[(SYNTAX-TABLE-ENTRY @i[syntax-table] @i[symbol]) @yl[] @i[descriptor] @r[or] @i[false]]
Accesses the syntax descriptor associated with @i[symbol] in
@i[syntax-table]. Returns false if there is no such entry.
@begin[ProgramExample]
(SYNTAX-TABLE-ENTRY *STANDARD-SYNTAX-TABLE* 'QUOTE) @ev[] #{Syntax QUOTE}
(SYNTAX-TABLE-ENTRY *STANDARD-SYNTAX-TABLE* 'CAR) @ev[] @r[false]
@end[ProgramExample]
Syntax table entries may be created or altered using
@wt[(SET (SYNTAX-TABLE-ENTRY ...) ...)]
or by using @tc[DEFINE-SYNTAX]. On assignment, @i[descriptor] may
be false, in which case @i[symbol] loses any syntax table entry it
may have had. This allows it to be bound as a variable using
@tc[DEFINE] or @tc[LET], for example.
@enddesc[SYNTAX-TABLE-ENTRY]
@section[Defining syntax]
@descN[
F1="(DEFINE-SYNTAX @i[symbol] @i[descriptor]) @yl[] @i[undefined]",
FN1="DEFINE-SYNTAX",
F2="(DEFINE-SYNTAX (@i[symbol] . @i[vars]) . @i[body]) @yl[] @i[undefined]"
]
Sets @i[symbol]'s syntax table entry in the syntax table of the
environment in which the @tc[DEFINE-SYNTAX] form is being evaluated.
The second form is an abbreviation for an equivalent expression
of the first form involving @tc[MACRO-EXPANDER]:
@begin[ProgramExample]
(DEFINE-SYNTAX (@i[symbol] . @i[variables]) . @i[body])
@ce[]
(DEFINE-SYNTAX @i[symbol]
(MACRO-EXPANDER (@i[symbol] . @i[variables]) . @i[body]))
@end[ProgramExample]
Macros and @tc[MACRO-EXPANDER] are explained below.
As with @tc[(SET (SYNTAX-TABLE-ENTRY ...) ...)], @i[descriptor] may
be false, in which case @i[symbol] loses any syntax table entry it
may have had. This allows it to be bound as a variable using
@tc[DEFINE] or @tc[LET], for example.
Note that @tc[DEFINE-SYNTAX] forms have no effect
at compile time. Using them indiscriminately may lead to code
which behaves differently depending on what compiler is being used.
For example, a use of the special form defined by a @tc[DEFINE-SYNTAX]
form later on in the same file in which the @tc[DEFINE-SYNTAX] form
occurs may be seen as a valid special form reference by the standard
compiler, but may be treated as a call by TC.
@begin[ProgramExample]
(DEFINE-SYNTAX (REPEAT N . CODE)
`(LET ((COUNT ,N)
(THUNK (LAMBDA () ,@@CODE)))
(DO ((COUNT COUNT (- COUNT 1)))
((<= COUNT 0) NIL)
(THUNK))))
@end[ProgramExample]
@enddescN[]
@section[Local syntax]
Reserved words may be defined at compile time using @tc[LET-SYNTAX]
and @tc[DEFINE-LOCAL-SYNTAX]. Syntax defined this way is called
@iix[local syntax] and is in effect only at compile time, not at run
time.
Local syntax is block structured, much as variables are. The outermost
local syntax contour is the point at which a compiler is invoked,
which usually means a file boundary. Inner contours are introduced
by @tc[LET-SYNTAX] forms.
Put another way, a local syntax table is created whenever a compiler
is invoked (@tc[LOAD], @tc[COMFILE], @tc[EVAL]) and whenever a
@tc[LET-SYNTAX] form is compiled. Entries are created in a local
syntax table at compile time for syntax defined initially by the
@tc[LET-SYNTAX] form and later when the compiler encounters
@tc[DEFINE-LOCAL-SYNTAX] forms. The syntax table is used at compile
time and is otherwise unavailable.
@desc[(LET-SYNTAX @i[specs] . @i[body]) @yl[] @i[value-of-body]]
Defines macros locally to @i[body]. Yields the value of @i[body],
an implicit block. Each @i[spec] should be either
@begin[ProgramExample]
(@i[symbol] @i[descriptor])
@end[ProgramExample]
or
@begin[ProgramExample]
((@i[symbol] . @i[vars]) . @i[body])
@end[ProgramExample]
in analogy to @tc[DEFINE-SYNTAX].
The @i[descriptor] and @i[body] forms in @i[specs] will not necessarily
run in an environment which is at all related to the environment in
which the program in which the @tc[LET-SYNTAX] form occurred will
be run, because compilation may occur independently of execution.
TC executes these forms in @tc[(TC-MACRO-DEFINITION-ENV)]; see page
@pageref[TC-MACRO-DEFINITION-ENV]. The standard compiler uses the
locale with which the syntax table passed to it is associated. This
is implementation-dependent, and subject to change. For this reason,
it is best to write local macros in such a way that no free variables
or special forms are used, other than those in the standard system
environment, that is, those defined to be part of the @Tau[] language.
This disclaimer does not apply to the @i[body] of the @tc[LET-SYNTAX] form,
which is evaluated (except for syntax) exactly as if the @tc[LET-SYNTAX]
expression were a @tc[BLOCK] expression.
@begin[ProgramExample]
(LET-SYNTAX ((KWOTE (SYNTAX-TABLE-ENTRY *STANDARD-SYNTAX-TABLE*
'QUOTE)))
(KWOTE (A B C)))@tindex[KWOTE]
@ev[] (A B C)
(LET-SYNTAX ((SET NIL)) (LET ((SET LIST) (X 5)) (SET X 8))) @ev[] (5 8)
(LET-SYNTAX (((MAC X) `'(X = ,X))) (MAC Y)) @ev[] (X = Y)
@end[ProgramExample]
@BeginInset[Bug:]
@Timp[] 2.7 doesn't implement @tc[LET-SYNTAX].
@EndInset[]
@EndDesc[LET-SYNTAX]
@info[NOTES="Special form"]
@descN[
F1="(DEFINE-LOCAL-SYNTAX @i[symbol] @i[descriptor]) @yl[] @i[undefined]",
FN1="DEFINE-LOCAL-SYNTAX",
F2="(DEFINE-LOCAL-SYNTAX (@i[symbol] . @i[vars]) . @i[body]) @yl[] @i[undefined]",
]
Defines syntax locally to the body of the nearest enclosing
@tc[LET-SYNTAX] form, or, if the @tc[DEFINE-LOCAL-SYNTAX] does not
appear inside a @tc[LET-SYNTAX] form, then to the file or outermost
expression in which it occurs. Forward references are not defined
to work; the @tc[DEFINE-LOCAL-SYNTAX] form should appear prior to any use of
@i[symbol] as a reserved word.
The syntax of @tc[DEFINE-LOCAL-SYNTAX] is analogous to that of
@tc[DEFINE-SYNTAX].
In general, @tc[DEFINE-LOCAL-SYNTAX] should be used for syntax which is
to be available only within the file in which it occurs. If
a syntax definition is needed for several files, then they
should be made available in some locale's syntax table by evaluating
@tc[DEFINE-SYNTAX] forms in that locale, and then that locale's syntax table
should be used when compiling or loading the file (see the @tc[SYNTAX-TABLE]
file header clause, page @pageref[SYNTAX-TABLE]).
@begin[group]
@BeginInset[Note:]
To ease incremental debugging, the standard compiler in @Timp[]
2.7 causes syntax defined with @tc[DEFINE-LOCAL-SYNTAX] to be
retained indefinitely; that is, they are entered into the syntax
table of the locale which was passed to @tc[LOAD]. Programs should
not rely on this feature,
however, or code may behave differently when compiled using TC.
@EndInset[]
@end[group]
@EndDescN[]
@section[Macro expanders]
@info[NOTES="Special form"]
@desc[(MACRO-EXPANDER (@i[identification] . @i[variables]) . @i[body]) @yl[] @i[macro-expander]]
Yields a macro expander. A macro expander is a kind of syntax
descriptor, and may therefore be stored in a syntax table. When a
compiler using a symbol table @i[S] encounters a form whose car is
a symbol, and the entry in @i[S] for that symbol is the object yielded
by a @tc[MACRO-EXPANDER]-expression, then the macro expander
is invoked; that is, its
@i[variables] are bound to the rest of form (as with one level of
@tc[DESTRUCTURE] binding), the @i[body] (an implicit block) is evaluated,
and the value is returned to the compiler. The compiler then compiles that
form in place of the original one.
The lexical context of @i[body] is that of the @tc[MACRO-EXPANDER] form
(augmented by the bindings of @i[variables], of course), as with
@tc[LAMBDA].
@begin[ProgramExample]
(DEFINE M (MACRO-EXPANDER (FOO X Y Z) `(LIST 'FIRST ',X ,Y ,Z)))
(INVOKE-MACRO-EXPANDER M '(BAR QUOTED (+ 1 2) (* 3 4)))
@ev[] (LIST 'FIRST 'QUOTED (+ 1 2) (* 3 4))
(DEFINE L (MAKE-LOCALE *STANDARD-ENV* NIL))
(SET (SYNTAX-TABLE-ENTRY (ENV-SYNTAX-TABLE L) 'BAR) M)
(EVAL '(BAR QUOTED (+ 1 2) (* 3 4)) L) @ev[] (FIRST QUOTED 3 12)
(DEFINE-SYNTAX FOO
(MACRO-EXPANDER (FOO THING FORM)
`(LIST ,FORM ',THING)))
(FOO (CONS 1 2) (CONS 3 5)) @ev[] ((3 . 5) (CONS 1 2))
@end[ProgramExample]
@tc[DESTRUCTURE] (page @PageRef[destructure]) and
backquote (page @PageRef[backquote section]) are useful in writing
macro expansion procedures, the first for taking apart the
form which is to be expanded, the second for constructing the resultant code
from templates.
Note that for a macro definition to take effect at compile time, it
must either be present in the syntax table being used by the
compiler (see page @pageref[SYNTAX-TABLE]), or defined locally
using @tc[LET-SYNTAX] or @tc[DEFINE-LOCAL-SYNTAX].
@enddesc[MACRO-EXPANDER]
@desc[(MACRO-EXPANDER? @i[descriptor]) @yl[] @i[boolean]]
Returns true if @i[descriptor], which must be a syntax descriptor,
is a macro expander.
@begin[ProgramExample]
(MACRO-EXPANDER? (MACRO-EXPANDER (FOO X) X)) @ev[] @r[true]
@end[ProgramExample]
@enddesc[MACRO-EXPANDER?]
@desc[(INVOKE-MACRO-EXPANDER @i[descriptor] @i[form]) @yl[] @i[new-form]]
Invokes the macro expansion procedure for @i[descriptor], which must
be a macro expander. (See @tc[MACRO-EXPANDER], above.)
@begin[ProgramExample]
(INVOKE-MACRO-EXPANDER (MACRO-EXPANDER (FOO X) `(LAMBDA () ,X))
'(BAZ (+ 1 2)))
@ev[]
(LAMBDA () (+ 1 2))
@end[ProgramExample]
@enddesc[INVOKE-MACRO-EXPANDER]
@desc[(MACRO-EXPAND @i[form syntax-table]) @yl[] @i[new-form]]
Performs one macro expansion on the @i[form], if it is a list whose
car is a symbol, there is an entry in the given @i[syntax-table] for
that symbol, and that entry is a macro expander.
@EndDesc[MACRO-EXPAND]